package jmf;

import java.io.*;
import java.awt.*;
import java.util.*;
import javax.media.*;
import javax.swing.*;
import java.awt.event.*;
import javax.media.format.*;
import javax.media.control.*;
import javax.media.protocol.*;
import jmf.network.NetworkRawDataSource;

public class MediaApp extends JFrame implements ControllerListener {

  public MediaApp() {
    initComponents();
    loadImages();
    cacheControls();
    initPlayer();
  }
   
  private void loadImages() {
    Class c = getClass();
    playButtonImg = new ImageIcon(c.getResource("/resources/play.png"));
    pauseButtonImg = new ImageIcon(c.getResource("/resources/pause.png"));
    soundButtonImg = new ImageIcon(c.getResource("/resources/sound_ok.png"));
    muteButtonImg = new ImageIcon(c.getResource("/resources/sound_mute.png"));
  }

  private void cacheControls() {
    allControls = new ArrayList<Component>(8);
    networkControls = new ArrayList<Component>(1);

    allControls.add(mediaScrollBar);
    allControls.add(stopButton);
    allControls.add(playPauseButton);
    allControls.add(advanceButton);
    allControls.add(slowButton);
    allControls.add(fastButton);
    allControls.add(volumeButton);
    allControls.add(volumeSlider);

    networkControls.add(stopButton);

    minimumSize = getMinimumSize();
  }

  private void initPlayer() {
    player = null;
    enableControls(false);
    statusLabel.setText("Stand-by");

    timer = new javax.swing.Timer(250, new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        updateTime();
      }
    });
  }

  @SuppressWarnings("unchecked")
  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
  private void initComponents() {

    playPauseButton = new javax.swing.JLabel();
    advanceButton = new javax.swing.JLabel();
    fastButton = new javax.swing.JLabel();
    slowButton = new javax.swing.JLabel();
    stopButton = new javax.swing.JLabel();
    jPanel2 = new javax.swing.JPanel();
    statusLabel = new javax.swing.JLabel();
    timeLabel = new javax.swing.JLabel();
    volumeButton = new javax.swing.JLabel();
    volumeSlider = new javax.swing.JSlider();
    mediaScrollBar = new javax.swing.JScrollBar();
    mediaPanel = new javax.swing.JPanel();
    jMenuBar1 = new javax.swing.JMenuBar();
    jMenu1 = new javax.swing.JMenu();
    openFileMenuItem = new javax.swing.JMenuItem();
    openRemoteMenuItem = new javax.swing.JMenuItem();
    closeMenuItem = new javax.swing.JMenuItem();
    jSeparator1 = new javax.swing.JSeparator();
    exitMenuItem = new javax.swing.JMenuItem();
    jMenu2 = new javax.swing.JMenu();
    aboutMenuItem = new javax.swing.JMenuItem();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setTitle("MediaApp");
    setFont(new java.awt.Font("Arial", 0, 9));
    setMinimumSize(new java.awt.Dimension(438, 140));

    playPauseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/play.png"))); // NOI18N
    playPauseButton.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseClicked(java.awt.event.MouseEvent evt) {
        playPauseButtonMouseClicked(evt);
      }
    });

    advanceButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/advance.png"))); // NOI18N
    advanceButton.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseClicked(java.awt.event.MouseEvent evt) {
        advanceButtonMouseClicked(evt);
      }
    });

    fastButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/fast.png"))); // NOI18N
    fastButton.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseClicked(java.awt.event.MouseEvent evt) {
        fastButtonMouseClicked(evt);
      }
    });

    slowButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/slow.png"))); // NOI18N
    slowButton.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseClicked(java.awt.event.MouseEvent evt) {
        slowButtonMouseClicked(evt);
      }
    });

    stopButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/stop.png"))); // NOI18N
    stopButton.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseClicked(java.awt.event.MouseEvent evt) {
        stopButtonMouseClicked(evt);
      }
    });

    jPanel2.setBackground(new java.awt.Color(0, 0, 0));

    statusLabel.setForeground(new java.awt.Color(255, 255, 255));
    statusLabel.setText(" ");

    timeLabel.setForeground(new java.awt.Color(255, 255, 255));
    timeLabel.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
    timeLabel.setText(" ");

    javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
    jPanel2.setLayout(jPanel2Layout);
    jPanel2Layout.setHorizontalGroup(
      jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(jPanel2Layout.createSequentialGroup()
        .addComponent(statusLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 300, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addGap(18, 18, 18)
        .addComponent(timeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 101, Short.MAX_VALUE))
    );
    jPanel2Layout.setVerticalGroup(
      jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
        .addComponent(statusLabel)
        .addComponent(timeLabel))
    );

    volumeButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/sound_ok.png"))); // NOI18N
    volumeButton.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseClicked(java.awt.event.MouseEvent evt) {
        volumeButtonMouseClicked(evt);
      }
    });

    volumeSlider.setFocusable(false);
    volumeSlider.addChangeListener(new javax.swing.event.ChangeListener() {
      public void stateChanged(javax.swing.event.ChangeEvent evt) {
        volumeSliderStateChanged(evt);
      }
    });

    mediaScrollBar.setBlockIncrement(200);
    mediaScrollBar.setMaximum(10000);
    mediaScrollBar.setOrientation(javax.swing.JScrollBar.HORIZONTAL);
    mediaScrollBar.setVisibleAmount(2);
    mediaScrollBar.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
      public void adjustmentValueChanged(java.awt.event.AdjustmentEvent evt) {
        mediaScrollBarAdjustmentValueChanged(evt);
      }
    });

    mediaPanel.setBackground(new java.awt.Color(0, 0, 0));
    mediaPanel.setFocusCycleRoot(true);
    mediaPanel.setFocusable(false);

    javax.swing.GroupLayout mediaPanelLayout = new javax.swing.GroupLayout(mediaPanel);
    mediaPanel.setLayout(mediaPanelLayout);
    mediaPanelLayout.setHorizontalGroup(
      mediaPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGap(0, 419, Short.MAX_VALUE)
    );
    mediaPanelLayout.setVerticalGroup(
      mediaPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGap(0, 0, Short.MAX_VALUE)
    );

    jMenu1.setText("File");

    openFileMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
    openFileMenuItem.setText("Play file media");
    openFileMenuItem.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        openFileMenuItemActionPerformed(evt);
      }
    });
    jMenu1.add(openFileMenuItem);

    openRemoteMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_A, java.awt.event.InputEvent.CTRL_MASK));
    openRemoteMenuItem.setText("Play remote media");
    openRemoteMenuItem.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        openRemoteMenuItemActionPerformed(evt);
      }
    });
    jMenu1.add(openRemoteMenuItem);

    closeMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_W, java.awt.event.InputEvent.CTRL_MASK));
    closeMenuItem.setText("Close");
    closeMenuItem.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        closeMenuItemActionPerformed(evt);
      }
    });
    jMenu1.add(closeMenuItem);
    jMenu1.add(jSeparator1);

    exitMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ESCAPE, 0));
    exitMenuItem.setText("Exit");
    exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        exitMenuItemActionPerformed(evt);
      }
    });
    jMenu1.add(exitMenuItem);

    jMenuBar1.add(jMenu1);

    jMenu2.setText("Help");

    aboutMenuItem.setText("About");
    jMenu2.add(aboutMenuItem);

    jMenuBar1.add(jMenu2);

    setJMenuBar(jMenuBar1);

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
        .addComponent(stopButton)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(playPauseButton)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(advanceButton)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
        .addComponent(slowButton)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(fastButton)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 78, Short.MAX_VALUE)
        .addComponent(volumeButton)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(volumeSlider, javax.swing.GroupLayout.PREFERRED_SIZE, 117, javax.swing.GroupLayout.PREFERRED_SIZE))
      .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
      .addComponent(mediaScrollBar, javax.swing.GroupLayout.DEFAULT_SIZE, 419, Short.MAX_VALUE)
      .addComponent(mediaPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
    );
    layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
        .addComponent(mediaPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(mediaScrollBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
          .addComponent(slowButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
          .addComponent(advanceButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
          .addComponent(playPauseButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
          .addComponent(stopButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
          .addComponent(fastButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
          .addComponent(volumeButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
          .addComponent(volumeSlider, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
    );

    pack();
  }// </editor-fold>//GEN-END:initComponents

    private void playPauseButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_playPauseButtonMouseClicked
      if (isPlaying)
        player.stop();
      else
        player.start();

      setPlayPauseButton(isPlaying = !isPlaying);
    }//GEN-LAST:event_playPauseButtonMouseClicked

    private void openFileMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openFileMenuItemActionPerformed
      JFileChooser fc = new JFileChooser();
      fc.setDialogTitle("MediaApp - Select a media to play");

      if (fc.showOpenDialog(this) != JFileChooser.APPROVE_OPTION)
        return;

      File file = fc.getSelectedFile();

      try {
        openFileMedia(file);
        isRemoteMedia = false;
      }
      catch (IOException e) {
        reportError(
          "Error opening file " + file.getName(), e
        );
        player = null;
      }
      catch (NoPlayerException e) {
        reportError(
          "No player in this system supports the media " + file.getName(), e
        );
        player = null;
      }
    }//GEN-LAST:event_openFileMenuItemActionPerformed

    private void closeMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeMenuItemActionPerformed
      closeMedia();
    }//GEN-LAST:event_closeMenuItemActionPerformed

    private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed
      closeMedia();
      System.exit(0);
    }//GEN-LAST:event_exitMenuItemActionPerformed

    private void volumeButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_volumeButtonMouseClicked
      try {
        boolean mute = gainControl.getMute();
        gainControl.setMute(!mute);
        volumeSlider.setEnabled(mute);
        volumeButton.setIcon(mute ? soundButtonImg : muteButtonImg);
      } catch (NullPointerException e) {
      }
    }//GEN-LAST:event_volumeButtonMouseClicked

    private void volumeSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_volumeSliderStateChanged
      float db = volumeSlider.getValue() / (float)volumeSlider.getMaximum();
      
      try {
        gainControl.setLevel(Math.min(db, 1.0f));
      } catch (Exception e) {
      }
    }//GEN-LAST:event_volumeSliderStateChanged

    private void slowButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_slowButtonMouseClicked
      player.setRate(player.getRate() - RATE_DELTA);
    }//GEN-LAST:event_slowButtonMouseClicked

    private void fastButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_fastButtonMouseClicked
      player.setRate(player.getRate() + RATE_DELTA);
    }//GEN-LAST:event_fastButtonMouseClicked

    private void advanceButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_advanceButtonMouseClicked
      player.setMediaTime(new Time(player.getMediaTime().getSeconds() + 60));
    }//GEN-LAST:event_advanceButtonMouseClicked

    private void mediaScrollBarAdjustmentValueChanged(java.awt.event.AdjustmentEvent evt) {//GEN-FIRST:event_mediaScrollBarAdjustmentValueChanged
      if (!evt.getValueIsAdjusting()) {
        int val = evt.getValue();
        if (val != lastScrollValue)
          setTime(val);
      }
    }//GEN-LAST:event_mediaScrollBarAdjustmentValueChanged

    private void stopButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_stopButtonMouseClicked
      closeMedia();
    }//GEN-LAST:event_stopButtonMouseClicked

    private void openRemoteMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openRemoteMenuItemActionPerformed
      String host = "localhost", file = "delta.mpg";

      try {
        openRemoteMedia(host, file);
        isRemoteMedia = true;
      }
      catch (IOException e) {
        reportError(
          "Error opening file " + file, e
        );
        player = null;
      }
      catch (NoPlayerException e) {
        reportError(
          "No player in this system supports the media " + file, e
        );
        e.printStackTrace();
        player = null;
      }
    }//GEN-LAST:event_openRemoteMenuItemActionPerformed

  public void controllerUpdate(ControllerEvent e) {
    if (e instanceof AudioDeviceUnavailableEvent) {
      reportError("Audio device unavailable.");
      closeMedia();
    }
    else if (e instanceof ControllerErrorEvent) {
      reportError("Controller error. Media not supported.");
      closeMedia();
    }
    else if (e instanceof DataLostErrorEvent) {
      reportError("Data lost error.");
      closeMedia();
    }
    else if (e instanceof TransitionEvent) {
      TransitionEvent t = (TransitionEvent)e;

      switch (t.getCurrentState()) {
        case Player.Unrealized:
          setStatus("Wait");
          break;

        case Player.Realizing:
          setStatus("Realizing");
          break;

        case Player.Realized:
          setupVisualComponent();
          setupVolume();
          setStatus("Loaded");
          break;

        case Player.Prefetching:
          setStatus("Loading");
          break;

        case Player.Prefetched:
          setStatus("Paused");
          break;
        
        case Player.Started:
          if (mediaPanel.getComponentCount() == 0)
            setupVisualComponent(600, 480);

          setStatus("Playing");
          break;
      }

      if (e instanceof EndOfMediaEvent) {
        player.setMediaTime(new Time(0));
        setStatus("Done");
        setPlayPauseButton(isPlaying = false);
      }
    }
  }

  private void updateTime() {
    Time duration = player.getDuration();
    Time elapsed = player.getMediaTime();

    if (!isRemoteMedia)
      timeLabel.setText(formatTime(elapsed) + " / " + formatTime(duration));
    else
      timeLabel.setText(formatTime(elapsed));

    if (mediaScrollBar.getValueIsAdjusting())
      return;

    if (duration == Player.DURATION_UNKNOWN ||
        duration == Player.DURATION_UNBOUNDED) {
      lastScrollValue = 0;
      mediaScrollBar.setValue(0);
    }
    else {
      long elapsedN = elapsed.getNanoseconds();
      double rate = elapsedN / (double)duration.getNanoseconds();
      int val = (int)(rate * mediaScrollBar.getMaximum());
      lastScrollValue = val;
      mediaScrollBar.setValue(val);
    }
  }

  private void setTime(int scrollVal) {
    Time duration = player.getDuration();

    if (duration != Player.DURATION_UNKNOWN &&
        duration != Player.DURATION_UNBOUNDED) {
      double rate = (double)scrollVal / mediaScrollBar.getMaximum();
      long durationN = duration.getNanoseconds();
      long posN = (long)(rate * durationN);
      player.setMediaTime(new Time(posN));
    }

    updateTime();  
  }

  private void openFileMedia(File file)
          throws IOException, NoPlayerException {
    closeMedia();

    lastScrollValue = 0;
    filename = file.getName();

    player = Manager.createPlayer(file.toURI().toURL());
    player.addControllerListener(this);
    player.start();
    
    timer.start();
    enableControls(true);
    setPlayPauseButton(true);
  }

  private void openRemoteMedia(String host, String file)
          throws IOException, NoPlayerException {
    closeMedia();

    filename = file;

    DataSource source = new NetworkRawDataSource(host);
    source.connect();
    
    player = Manager.createPlayer(source);
    player.addControllerListener(this);
    player.start();

    timer.start();
    enableControls(false);
    enableNetworkControls(true);
    setPlayPauseButton(true);
  }

  private void closeMedia() {
    if (player != null) {
      player.close();
      timer.stop();
      player.deallocate();
      player = null;
    }

    setPlayerSize(0, 10);
    enableControls(false);
    statusLabel.setText("Stand-by");
  }

  private void enableControls(boolean enabled) {
    for (Component c : allControls)
      c.setEnabled(enabled);
  }

  private void enableNetworkControls(boolean enabled) {
    for (Component c : networkControls)
      c.setEnabled(enabled);
  }

  private void setupVisualComponent() {
    Component media = player.getVisualComponent();
    Dimension d = getMediaSize();

    if (d != null) {
      setPlayerSize(d.width, d.height);
      mediaPanel.setLayout(new BorderLayout());
      mediaPanel.add(media, BorderLayout.CENTER);
    }
  }

  private void setupVisualComponent(int w, int h) {
    Component media = player.getVisualComponent();
    setPlayerSize(w, h);
    mediaPanel.setLayout(new BorderLayout());
    mediaPanel.add(media, BorderLayout.CENTER);
  }

  private void setupVolume() {
    gainControl = player.getGainControl();

    if (gainControl == null)
      return;

    gainControl.setMute(false);
    volumeButton.setIcon(soundButtonImg);
    volumeSlider.setValue(
      Math.min((int)(100 * gainControl.getLevel()), 100)
    );
  }

  private void setPlayerSize(int width, int height) {
    int widthD = Math.max(0, width - getMinimumSize().width);
    
    setSize(minimumSize.width + widthD,
            minimumSize.height + height);
  }

  private Dimension getMediaSize() {
    try {
      FormatControl formatC = (FormatControl)player.getControl(
        "javax.media.control.FormatControl"
      );

      VideoFormat format = (VideoFormat)formatC.getFormat();
      return format.getSize();
    } catch (Exception e) {
      return null;
    }
  }

  private void setStatus(String status) {
    String str = filename + " - " + status;
    statusLabel.setText(str);
  }

  private void setPlayPauseButton(boolean isPlay) {
    playPauseButton.setIcon(isPlay ? pauseButtonImg : playButtonImg);
    isPlaying = isPlay;
  }

  private void reportError(String error, Exception e) {
    reportError(error + ". Message: " + e.getMessage());
  }

  private void reportError(String error) {
    JOptionPane.showMessageDialog(
      this, error, "MediaApp - Error",
      JOptionPane.ERROR_MESSAGE
    );
  }

  private String formatTime(Time t) {
    int time = (int)t.getSeconds();
    int sec = time % 60; time /= 60;
    int min = time % 60; time /= 60;
    int hours = time;

    String str = String.format("%02d:%02d", min, sec);

    if (hours != 0)
      str = hours + ":" + str;

    return str;
  }

  public static void main(String args[]) {
    java.awt.EventQueue.invokeLater(new Runnable() {
      public void run() {
        new MediaApp().setVisible(true);
      }
    });
  }

  // <editor-fold defaultstate="collapsed" desc="Variable declarations">
  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JMenuItem aboutMenuItem;
  private javax.swing.JLabel advanceButton;
  private javax.swing.JMenuItem closeMenuItem;
  private javax.swing.JMenuItem exitMenuItem;
  private javax.swing.JLabel fastButton;
  private javax.swing.JMenu jMenu1;
  private javax.swing.JMenu jMenu2;
  private javax.swing.JMenuBar jMenuBar1;
  private javax.swing.JPanel jPanel2;
  private javax.swing.JSeparator jSeparator1;
  private javax.swing.JPanel mediaPanel;
  private javax.swing.JScrollBar mediaScrollBar;
  private javax.swing.JMenuItem openFileMenuItem;
  private javax.swing.JMenuItem openRemoteMenuItem;
  private javax.swing.JLabel playPauseButton;
  private javax.swing.JLabel slowButton;
  private javax.swing.JLabel statusLabel;
  private javax.swing.JLabel stopButton;
  private javax.swing.JLabel timeLabel;
  private javax.swing.JLabel volumeButton;
  private javax.swing.JSlider volumeSlider;
  // End of variables declaration//GEN-END:variables
  // </editor-fold>

  private Player player;
  private String filename;
  private GainControl gainControl;
  private javax.swing.Timer timer;

  private boolean isPlaying;
  private int lastScrollValue;
  private boolean isRemoteMedia;

  private Dimension minimumSize;
  private ImageIcon playButtonImg, pauseButtonImg;
  private ImageIcon soundButtonImg, muteButtonImg;
  private java.util.List<Component> allControls, networkControls;

  private static final float RATE_DELTA = 0.2f;
}
